# big model: weight restriction on BETAs (10% ~ 90%) 2016--2022

# import packages
import numpy as np
import pandas as pd
from pystoned import uCNLS
from pystoned.constant import CET_MULT, FUN_COST, RTS_CRS
from pyomo.environ import Constraint


# load data
df = pd.read_excel("StoNED_data_2016_2022_19082025.xls")

# input: KOPEX
y = df["KOPEX"]
y = np.asmatrix(y).T

# outputs (incl. bad output)
x1 = df['Energia']
x1 = np.asmatrix(x1).T
x2 = df['Verkkopituus']
x2 = np.asmatrix(x2).T
x3 = df['Käyttäjämäärä']
x3 = np.asmatrix(x3).T
x4 = -df['NKA']/1000
x4 = np.asmatrix(x4).T
x = np.concatenate((x1, x2, x3, x4), axis=1)

# bad output
b = df['KAH']
b = np.asmatrix(b).T

# contextual Variable: z
z1 = df['L/K suhde']
z1 = np.asmatrix(z1).T
z2 = df['häviösähköprosentti']
z2 = np.asmatrix(z2).T
z = np.concatenate((z1, z2), axis=1)

# define and solve the basic CNLS model
res = uCNLS.uCNLS(y, x, b, z, cet = CET_MULT, fun = FUN_COST, rts = RTS_CRS)
# weight restriction on BETAs (10% ~ 90%)
def constraint_rule_beta1(model, i, j):
    upperbound = [3.218, 0.430, 0.080, 24.421 ]
    return model.beta[i, j] <= upperbound[j]

res.__model__.beta_constraint_rule1 = Constraint(res.__model__.I,
                                                res.__model__.J,
                                                rule=constraint_rule_beta1,
                                                doc='beta constraint1')

def constraint_rule_beta2(model, i, j):
    lowbound = [0.020, 0.000, 0.002, 0.002 ]
    return model.beta[i, j] >= lowbound[j]

res.__model__.beta_constraint_rule2 = Constraint(res.__model__.I,
                                                res.__model__.J,
                                                rule=constraint_rule_beta2,
                                                doc='beta constraint2')

# weight restriction on DELTA (10% ~ 90%)
def constraint_rule_delta1(model, i, l):
    upperbound = [0.242]
    return model.delta[i, l] <= upperbound[l]

res.__model__.delta_constraint_rule1 = Constraint(res.__model__.I,
                                                res.__model__.L,
                                                rule=constraint_rule_delta1,
                                                doc='delta constraint1')

def constraint_rule_delta2(model, i, l):
    lowbound = [-3.322]
    return  model.delta[i, l] >= lowbound[l]

res.__model__.delta_constraint_rule2 = Constraint(res.__model__.I,
                                                res.__model__.L,
                                                rule=constraint_rule_delta2,
                                                doc='delta constraint2')
res.optimize()

# store the results
writer = pd.ExcelWriter('2016_2022_19082025_CNLS_tulokset_weight10_gams.xlsx', engine='xlsxwriter')
pd.DataFrame(res.get_beta()).to_excel(writer, sheet_name='beta')
pd.DataFrame(res.get_delta()).to_excel(writer, sheet_name='delta')
pd.DataFrame(res.get_lamda()).to_excel(writer, sheet_name='lamda')
pd.DataFrame(res.get_residual()).to_excel(writer, sheet_name='residual')

writer.save()
